﻿#pragma once
#include <vector>               // 用于存储工作线程
#include <queue>                // 用于存储任务队列
#include <memory>               // 用于智能指针
#include <thread>               // 用于多线程
#include <mutex>                // 用于互斥锁
#include <condition_variable>   // 用于线程等待和通知
#include <future>               // 用于 std::future 和 std::packaged_task
#include <functional>           // 用于 std::function 和 std::bind
#include <stdexcept>            // 用于抛出异常
#include <utility>              // 用于 std::forward

class ThreadPool {
public:
    // 构造函数，threads 指定线程池中工作线程数量
    // 如果不指定，默认为硬件并发线程数
    explicit ThreadPool(size_t threads = std::thread::hardware_concurrency());

    // 禁止拷贝构造函数
    ThreadPool(const ThreadPool&) = delete;
    // 禁止拷贝赋值
    ThreadPool& operator=(const ThreadPool&) = delete;

    // 提交任务到线程池，返回 future 对象以获取结果
    // F: 可调用对象类型，Args: 参数类型包
    template<class F, class... Args>
    auto enqueue(F&& f, Args&&... args)
    -> std::future<typename std::result_of<F(Args...)>::type>;

    // 析构函数，停止所有线程并清理资源
    ~ThreadPool();

private:
    std::vector<std::thread> workers;               // 工作线程容器
    std::queue<std::function<void()>> tasks;        // 任务队列，存储待执行任务
    std::mutex queue_mutex;                         // 互斥锁，保护任务队列
    std::condition_variable condition;             // 条件变量，用于线程等待和唤醒
    bool stop;                                      // 标记线程池是否停止
};

// ------------------------
// 模板函数实现必须放在头文件中
// ------------------------
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
    // 推导任务返回类型
    using return_type = typename std::result_of<F(Args...)>::type;
    // 将任务封装为 shared_ptr<packaged_task>，支持异步返回值
    auto task = std::make_shared<std::packaged_task<return_type()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
    );

    // 获取 future 对象，用于主线程等待或获取任务结果
    std::future<return_type> res = task->get_future();

    {
        // 上锁保护任务队列
        std::unique_lock<std::mutex> lock(queue_mutex);

        // 如果线程池已停止，不允许提交任务
        if (stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");

        // 将任务加入队列，包装为无参 lambda 以便统一调用
        tasks.emplace([task]() { (*task)(); });
    }
    // 通知一个等待的工作线程，有新任务可执行
    condition.notify_one();
    // 返回 future 给调用者获取任务结果
    return res;
}
